package ar.uba.fi.tecnicas.juego;

import java.awt.*;
import java.util.*;
import java.util.List;

import ar.uba.fi.tecnicas.fabrica.*;
import ar.uba.fi.tecnicas.fabrica.exceptions.*;
import ar.uba.fi.tecnicas.juego.exceptions.*;
import ar.uba.fi.tecnicas.vista.IVistaFabrica;

public class Jugador extends Observable
{
	private String nombreJugador;
	private double capital;
	private Fabrica fabrica;
	
	public Jugador(String nombre, double capital)
	{
		this.nombreJugador = nombre;
		this.capital = capital;
		this.fabrica = new Fabrica();
	}
	
	public String getNombre()
	{
		return(this.nombreJugador);
	}
	
	public double getCapital()
	{
		return(this.capital);
	}
	
	public void agregarGanancia(double monto)
	{
		this.capital += monto;
		this.setChanged();
	}
	
	public void restarGastos(double gasto)
	{
		this.capital -= gasto;
		this.setChanged();
	}
	
	public boolean bancarrota()
	{
		if (this.getCapital() < 0)
		{
			return true;
		}			
		else
		{
			return false;
		}
	}
	
	public Maquina comprarMaquina(TipoMaquina tipo, Point posicion, int indexLinea) throws 
	TipoMaquinaFaltanteException,
	PosicionTerrenoOcupadaException,
	CapitalInsuficienteException
	{
		LineaProduccion linea = this.fabrica.getLineaProduccion(indexLinea);
		
		this.capitalSuficiente(tipo.getPrecio());
		
		PosicionTerreno posicionTerreno = new PosicionTerreno(posicion);
		
		// TODO: Crear MaquinaBuilder para poder manejar la creacion Maquina normal/control calidad desde un solo lugar.
		Maquina maquina = new Maquina(tipo, posicionTerreno);
			 
		this.restarGastos(tipo.getPrecio());
		
		linea.agregarItem(maquina);
		
		this.fabrica.getTerreno().setPosicion(posicionTerreno);
		
		this.notifyObservers();
		
		return maquina;
	}
	
	public void conectarMaquinas(Point posicionOrigen, Point posicionDestino) 
	throws 
		ItemsEnConexionConDiferentePadreException,
		CapitalInsuficienteException
	{
		IConectable origen = (IConectable)this.fabrica.getTerreno().getPosicion(posicionOrigen).getItem();
		IConectable destino = (IConectable)this.fabrica.getTerreno().getPosicion(posicionDestino).getItem();

		double distancia = Cinta.calcularDistancia(origen, destino);
		this.capitalSuficiente(distancia * ConfiguracionJuego.instancia.getPrecioMetroCinta());
		
		LineaProduccion linea = ((ItemLineaProduccion)origen).getLineaProduccion();

		Cinta cinta = new Cinta();
		linea.agregarItem(cinta);
		
		cinta.conectar(origen, destino);
		
		this.restarGastos(distancia * ConfiguracionJuego.instancia.getPrecioMetroCinta());
		
		this.notifyObservers();
	}
	
	public void comprarTerreno(Terreno terreno, Terreno.ModoAdquisicion modo) 
	throws
		CapitalInsuficienteException,
		FabricaConTerrenoException
	{		
		this.capitalSuficiente(terreno.getPrecio(modo));

		this.fabrica.setTerreno(terreno);

		this.restarGastos(terreno.getPrecio(modo));
		
		this.notifyObservers();
	}
	
	public void seleccionarPrimeraMaquina(int indexLineaProduccion, Point posicion)
	throws
		ItemNoPertenceALineaException,
		PrimerItemLineaConConexionEnEntradaException
	{
		LineaProduccion linea = this.fabrica.getLineaProduccion(indexLineaProduccion);
		
		PosicionTerreno posicionTerreno = this.fabrica.getTerreno().getPosicion(posicion);
		
		linea.setearPrimerItem((IConectable)posicionTerreno.getItem());		
	}
	
	public void ubicarSalidaFabrica(Point posicion) throws PosicionTerrenoOcupadaException
	{	
		this.fabrica.ubicarSalida(posicion);
		
		this.notifyObservers();
	}
	
	private void capitalSuficiente(double gasto) throws CapitalInsuficienteException
	{
		if(this.capital < gasto)
		{
			throw new CapitalInsuficienteException();			
		}
	}

	public void contabilizarGanancias() 
	{
		this.agregarGanancia(this.fabrica.calcularGanancia());
		
		this.notifyObservers();
	}

	public void producir() 
	throws
		MultiplesMaquinasControlCalidadException,
		LineaProduccionCircularException,
		UltimoItemSalidaFabricaRequeridoException,
		MaquinaControlCalidadNoUltimaPosicionException
	{
		this.fabrica.producir();		
	}

	public void crearLineaProduccion(String nombre) 
	{
		this.fabrica.crearLineaProduccion(nombre);
		
		this.notifyObservers();
	}

	public List<String> getLineasProduccion() 
	{
		List<String> nombres = new ArrayList<String>();
		
		for(LineaProduccion linea : this.fabrica.getLineasProduccion())
		{
			nombres.add(linea.getNombre());
		}
		
		return nombres;
	}

	public Dimension getDimensionTerreno() 
	{
		return new Dimension(
			this.fabrica.getTerreno().getAncho(), 
			this.fabrica.getTerreno().getAlto()
		);
	}

	public boolean posicionTerrenoOcupada(Point posicion) 
	{
		return this.fabrica.getTerreno().posicionOcupada(posicion);
	}

	public void agregarVistaFabrica(IVistaFabrica vista) 
	{
		this.fabrica.addObserver((Observer)vista);
		
		vista.setFabrica(this.fabrica);
	}
}
